using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Transforms;

namespace Game.Core
{
    // [AlwaysUpdateSystem]
    [UpdateInGroup(typeof(SimulationSystemGroup))]
    public unsafe partial class PropertySystem : SystemBase
    {
        EndSimulationEntityCommandBufferSystem ECBSystem;
        EntityCommandBuffer buffer;
        
        protected override void OnCreate()
        {
            ECBSystem = World.GetOrCreateSystemManaged<EndSimulationEntityCommandBufferSystem>();
            InitPropertyModifyQuery();
            InitAttackableQuery();
            InitDamageableQuery();
            InitMovableQuery();
        }

        protected override void OnUpdate()
        {
            buffer = ECBSystem.CreateCommandBuffer();
            Dependency = SchedulePropertyModifyJob(Dependency);
            // Dependency = new RefreshBasePropertyJob().ScheduleParallel(Dependency);
            // Dependency = new RefreshCurrentPropertyJob().ScheduleParallel(Dependency);
            Dependency = ScheduleAttackableRefreshJob(Dependency);
            Dependency = ScheduleDamageableRefreshJob(Dependency);
            Dependency = ScheduleMovalbeRefreshJob(Dependency);
        }

        #region PropertyModify
        
        EntityQuery m_ModifyQuery;
        
        private void InitPropertyModifyQuery()
        {
            var builder = new EntityQueryBuilder(Allocator.Temp);
            builder.AddAll(ComponentType.ReadWrite<PropertyModifier>());
            builder.AddAny(ComponentType.ReadWrite<PropertyData>());
            builder.AddAny(ComponentType.ReadWrite<Attackable>());
            builder.AddAny(ComponentType.ReadWrite<Damageable>());
            builder.AddAny(ComponentType.ReadWrite<Movable>());
            // builder.FinalizeQuery();
            m_ModifyQuery = GetEntityQuery(builder);
            builder.Dispose();
        }

        private JobHandle SchedulePropertyModifyJob(JobHandle handle)
        {
            var job = new PropertyModifyJob();
            job.PropertyModifierTypeHandle = GetBufferTypeHandle<PropertyModifier>();
            job.PropertyDataTypeHandle = GetComponentTypeHandle<PropertyData>();
            job.AttackableTypeHandle = GetComponentTypeHandle<Attackable>();
            job.DamageableTypeHandle = GetComponentTypeHandle<Damageable>();
            job.MovableTypeHandle = GetComponentTypeHandle<Movable>();
            return job.ScheduleParallel(m_ModifyQuery, handle);
        }

        #endregion

        #region AttackableRefresh

        EntityQuery m_AttackableQuery;

        protected void InitAttackableQuery()
        {
            var builder = new EntityQueryBuilder(Allocator.Temp);
            builder.AddAll(ComponentType.ReadWrite<PropertyData>());
            builder.AddAll(ComponentType.ReadWrite<Attackable>());
            // builder.FinalizeQuery();
            m_AttackableQuery = GetEntityQuery(builder);
            builder.Dispose(); 
        }
        
        private JobHandle ScheduleAttackableRefreshJob(JobHandle handle)
        {
            var job = new AttackableRefreshJob();
            job.DeltaTime = World.Time.DeltaTime;
            return job.ScheduleParallel(m_AttackableQuery, handle);
        }

        #endregion
        
        #region DamageableRefresh
        
        EntityQuery m_DamageableQuery;
        
        private void InitDamageableQuery()
        {
            var builder = new EntityQueryBuilder(Allocator.Temp);
            builder.AddAll(ComponentType.ReadWrite<PropertyData>());
            builder.AddAll(ComponentType.ReadWrite<Attackable>());
            // builder.FinalizeQuery();
            m_DamageableQuery = GetEntityQuery(builder);
            builder.Dispose();
        }

        private JobHandle ScheduleDamageableRefreshJob(JobHandle handle)
        {
            var job = new DamageableRefreshJob();
            job.DeltaTime = World.Time.DeltaTime;
            return job.ScheduleParallel(m_DamageableQuery, handle);
        }
        
        #endregion
        
        #region MovableRefresh
        
        EntityQuery m_MovableQuery;
        
        private void InitMovableQuery()
        {
            var builder = new EntityQueryBuilder(Allocator.Temp);
            builder.AddAll(ComponentType.ReadWrite<PropertyData>());
            builder.AddAll(ComponentType.ReadWrite<Movable>());
            // builder.FinalizeQuery();
            m_MovableQuery = GetEntityQuery(builder);
            builder.Dispose();
        }
        
        private JobHandle ScheduleMovalbeRefreshJob(JobHandle handle)
        {
            var job = new MovalbeRefreshJob();
            return job.ScheduleParallel(m_MovableQuery, handle);
        }

        #endregion
    }
}